﻿@using Xunit;
@using System.ComponentModel.DataAnnotations
@inherits TestContext

@code
{
    [Inject]
    private LibraryConfiguration LibraryConfiguration { get; set; } = new LibraryConfiguration();

    public FluentWizardTests()
    {
        this.Services.AddSingleton(LibraryConfiguration);
    }

    [Fact]
    public void FluentWizard_Left()
    {
        // Arrange && Act
        var cut = Render(@<FluentWizard>
        <Steps>
            <FluentWizardStep Label="Step1" Summary="Summary 1">
                Content 1
            </FluentWizardStep>
            <FluentWizardStep Label="Step2" Summary="Summary 2">
                Content 2
            </FluentWizardStep>
            <FluentWizardStep Label="Step3" Summary="Summary 3">
                Content 3
            </FluentWizardStep>
        </Steps>
    </FluentWizard>);

        // Assert
        cut.Markup.Contains("position=\"left\"");
        cut.Verify();
    }

    [Fact]
    public void FluentWizard_Top()
    {
        // Arrange && Act
        var cut = Render(@<FluentWizard StepperPosition="StepperPosition.Top">
        <Steps>
            <FluentWizardStep Label="Step1" Summary="Summary 1">
                Content 1
            </FluentWizardStep>
            <FluentWizardStep Label="Step2" Summary="Summary 2">
                Content 2
            </FluentWizardStep>
            <FluentWizardStep Label="Step3" Summary="Summary 3">
                Content 3
            </FluentWizardStep>
        </Steps>
    </FluentWizard>);

        // Assert
        cut.Markup.Contains("position=\"top\"");
        cut.Verify();
    }

    [Fact]
    public void FluentWizard_Disabled()
    {
        // Arrange && Act
        var cut = Render(@<FluentWizard>
        <Steps>
            <FluentWizardStep Label="Step1" Summary="Summary 1">
                Content 1
            </FluentWizardStep>
            <FluentWizardStep Disabled Label="Step2" Summary="Summary 2">
                Content 2
            </FluentWizardStep>
            <FluentWizardStep Label="Step3" Summary="Summary 3">
                Content 3
            </FluentWizardStep>
        </Steps>
    </FluentWizard>
    );

        // Assert
        cut.FindAll("li").Single(i => i.ToMarkup().Contains("disabled"));
    }

    [Fact]
    public void FluentWizard_NavigateNext()
    {
        var stepChangedIndex = 0;
        var stepChangedLabel = "";

        // Arrange
        var cut = Render(@<FluentWizard>
        <Steps>
            <FluentWizardStep Label="Step1" Summary="Summary 1" OnChange="@StepChanged">
                Content 1
            </FluentWizardStep>
            <FluentWizardStep Label="Step2" Summary="Summary 2" OnChange="@StepChanged">
                Content 2
            </FluentWizardStep>
            <FluentWizardStep Label="Step3" Summary="Summary 3" OnChange="@StepChanged">
                Content 3
            </FluentWizardStep>
        </Steps>
    </FluentWizard>
    );

        var nextButton = cut.Find("fluent-button[appearance='accent']");
        nextButton.Click();

        // Assert
        cut.FindAll("li")[1].ToMarkup().Contains("status=\"current\"");
        Assert.Equal(1, stepChangedIndex);
        Assert.Equal("Step2", stepChangedLabel);

        void StepChanged(FluentWizardStepChangeEventArgs e)
        {
            stepChangedIndex = e.TargetIndex;
            stepChangedLabel = e.TargetLabel;
        }
    }

    [Fact]
    public void FluentWizard_NavigatePrevious()
    {
        // Arrange
        var cut = Render(@<FluentWizard>
        <Steps>
            <FluentWizardStep Label="Step1" Summary="Summary 1">
                Content 1
            </FluentWizardStep>
            <FluentWizardStep Label="Step2" Summary="Summary 2">
                Content 2
            </FluentWizardStep>
            <FluentWizardStep Label="Step3" Summary="Summary 3">
                Content 3
            </FluentWizardStep>
        </Steps>
    </FluentWizard>
    );

        var nextButton = cut.Find("fluent-button[appearance='accent']");
        nextButton.Click();
        nextButton.Click();

        var previousButton = cut.Find("fluent-button");
        previousButton.Click();

        // Assert
        cut.FindAll("li")[1].ToMarkup().Contains("status=\"current\"");
    }

    [Fact]
    public void FluentWizard_NavigateWithBindedValue()
    {
        int stepIndex = 0;

        // Arrange
        var cut = Render(@<FluentWizard @bind-Value="@stepIndex">
        <Steps>
            <FluentWizardStep Label="Step1" Summary="Summary 1">
                Content 1
            </FluentWizardStep>
            <FluentWizardStep Label="Step2" Summary="Summary 2">
                Content 2
            </FluentWizardStep>
            <FluentWizardStep Label="Step3" Summary="Summary 3">
                Content 3
            </FluentWizardStep>
        </Steps>
    </FluentWizard>
    );

        var nextButton = cut.Find("fluent-button[appearance='accent']");
        nextButton.Click();

        // Assert
        cut.FindAll("li")[1].ToMarkup().Contains("status=\"current\"");
        Assert.Equal(1, stepIndex);
    }

    [Fact]
    public void FluentWizard_NavigateWithDisabled()
    {
        // Arrange
        var cut = Render(@<FluentWizard>
        <Steps>
            <FluentWizardStep Label="Step1" Summary="Summary 1">
                Content 1
            </FluentWizardStep>
            <FluentWizardStep Disabled Label="Step2" Summary="Summary 2">
                Content 2
            </FluentWizardStep>
            <FluentWizardStep Label="Step3" Summary="Summary 3">
                Content 3
            </FluentWizardStep>
        </Steps>
    </FluentWizard>);

        var nextButton = cut.Find("fluent-button[appearance='accent']");
        nextButton.Click();

        // Assert
        cut.FindAll("li")[2].ToMarkup().Contains("status=\"current\"");
    }

    [Theory]
    [InlineData(0)]
    [InlineData(1)]
    [InlineData(2)]
    public void FluentWizard_DeferredLoading(int nextCount)
    {
        // Arrange
        var cut = Render(@<FluentWizard>
        <Steps>
            <FluentWizardStep Label="Step1" Summary="Summary 1">
                Content 1
            </FluentWizardStep>
            <FluentWizardStep DeferredLoading Label="Step2" Summary="Summary 2">
                Content 2
            </FluentWizardStep>
            <FluentWizardStep DeferredLoading Label="Step3" Summary="Summary 3">
                Content 3
            </FluentWizardStep>
        </Steps>
    </FluentWizard>);

        for (int i = 0; i < nextCount; i++)
        {
            var nextButton = cut.Find("fluent-button[appearance='accent']");
            nextButton.Click();
        }

        // Assert
        cut.Verify(suffix: $"Count{nextCount}");
    }

    [Fact]
    public void FluentWizard_StepTemplate()
    {
        // Arrange
        var cut = Render(@<FluentWizard>
        <Steps>
            <FluentWizardStep>
                <StepTemplate>
                    @GetStepContent(context)
                </StepTemplate>
                <ChildContent>
                    Content 1
                </ChildContent>
            </FluentWizardStep>
            <FluentWizardStep>
                <StepTemplate>
                    @GetStepContent(context)
                </StepTemplate>
                <ChildContent>
                    Content 2
                </ChildContent>
            </FluentWizardStep>
        </Steps>
    </FluentWizard>
    );

        // Assert
        cut.Verify();

        string GetStepContent(FluentWizardStepArgs args)
        {
            return $"{args.Index} - {(args.Active ? "Active" : "Inactive")}";
        }
    }

    [Fact]
    public void FluentWizard_EditForm_EditContextIsValid()
    {
        var testRecord1 = new TestRecord
            {
                NumberBetween1and10 = 5,
            };

        var testRecord2 = new TestRecord
            {
                NumberBetween1and10 = 7,
            };

        var cut = Render(@<FluentWizard OnFinish="OnFinishHandler">
        <Steps>
            <FluentWizardStep>
                <FluentEditForm Model="testRecord1">
                    <DataAnnotationsValidator />
                    <FluentValidationSummary />
                    <FluentNumberField @bind-Value=testRecord1.NumberBetween1and10 />
                </FluentEditForm>
            </FluentWizardStep>
            <FluentWizardStep>
                <FluentEditForm Model="testRecord2">
                    <DataAnnotationsValidator />
                    <FluentValidationSummary />
                    <FluentNumberField @bind-Value=testRecord2.NumberBetween1and10 />
                </FluentEditForm>
            </FluentWizardStep>
        </Steps>
    </FluentWizard>
    );

        bool finishHandled = false;

        for (var i = 0; i < 2; i++)
        {
            var nextButton = cut.Find("fluent-button[appearance='accent']");
            nextButton.Click();
        }

        // Assert
        cut.Verify();

        void OnFinishHandler()
        {
            finishHandled = true;
        }

        Assert.True(finishHandled);
    }

    [Fact]
    public void FluentWizard_EditForm_EditContextIsInValid_OnNext()
    {
        int stepIndex = 0;

        var testRecord1 = new TestRecord
            {
                NumberBetween1and10 = 15,
            };

        var testRecord2 = new TestRecord
            {
                NumberBetween1and10 = 15,
            };

        var cut = Render(@<FluentWizard OnFinish="OnFinishHandler" @bind-Value="@stepIndex">
        <Steps>
            <FluentWizardStep>
                <FluentEditForm Model="testRecord1">
                    <DataAnnotationsValidator />
                    <FluentValidationSummary />
                    <FluentNumberField @bind-Value=testRecord1.NumberBetween1and10 />
                </FluentEditForm>
            </FluentWizardStep>
            <FluentWizardStep>
                <FluentEditForm Model="testRecord2">
                    <DataAnnotationsValidator />
                    <FluentValidationSummary />
                    <FluentNumberField @bind-Value=testRecord2.NumberBetween1and10 />
                </FluentEditForm>
            </FluentWizardStep>
        </Steps>
    </FluentWizard>
    );

        bool finishHandled = false;

        for (var i = 0; i < 2; i++)
        {
            var nextButton = cut.Find("fluent-button[appearance='accent']");
            nextButton.Click();
        }

        // Assert
        cut.Verify();

        void OnFinishHandler()
        {
            finishHandled = true;
        }

        Assert.False(finishHandled);
        Assert.Equal(0, stepIndex);
    }

    [Fact]
    public void FluentWizard_EditForm_EditContextIsInValid_OnFinish()
    {
        var testRecord1 = new TestRecord
            {
                NumberBetween1and10 = 5,
            };

        var testRecord2 = new TestRecord
            {
                NumberBetween1and10 = 15,
            };

        var cut = Render(@<FluentWizard OnFinish="OnFinishHandler">
        <Steps>
            <FluentWizardStep>
                <FluentEditForm Model="testRecord1">
                    <DataAnnotationsValidator />
                    <FluentValidationSummary />
                    <FluentNumberField @bind-Value=testRecord1.NumberBetween1and10 />
                </FluentEditForm>
            </FluentWizardStep>
            <FluentWizardStep>
                <FluentEditForm Model="testRecord2">
                    <DataAnnotationsValidator />
                    <FluentValidationSummary />
                    <FluentNumberField @bind-Value=testRecord2.NumberBetween1and10 />
                </FluentEditForm>
            </FluentWizardStep>
        </Steps>
    </FluentWizard>
    );

        bool finishHandled = false;

        for (var i = 0; i < 2; i++)
        {
            var nextButton = cut.Find("fluent-button[appearance='accent']");
            nextButton.Click();
        }

        // Assert
        cut.Verify();

        void OnFinishHandler()
        {
            finishHandled = true;
        }

        Assert.False(finishHandled);
    }

    [Theory]
    [InlineData(WizardStepSequence.Linear, 0, 0, 0, 2)]
    [InlineData(WizardStepSequence.Visited, 0, 1, 2, 0)]
    [InlineData(WizardStepSequence.Any, 2, 2, 2, 0)]
    public void FluentWizard_StepSequences(WizardStepSequence flexible,
        int clickable1, int clickable2, int clickable3, int indexFirstItem)
    {
        var currentIndex = 0;

        // Arrange && Act
        var cut = Render(@<FluentWizard StepSequence="@flexible" @bind-Value="@currentIndex">
        <Steps>
            <FluentWizardStep Label="Step1" Summary="Summary 1">
                Content 1
            </FluentWizardStep>
            <FluentWizardStep Label="Step2" Summary="Summary 2">
                Content 2
            </FluentWizardStep>
            <FluentWizardStep Label="Step3" Summary="Summary 3">
                Content 3
            </FluentWizardStep>
        </Steps>
    </FluentWizard>
    );

        // Assert before any click on Next button
        int clickableLinks1 = cut.FindAll("li[style*='cursor: pointer']").Count;
        Assert.Equal(clickable1, clickableLinks1);

        // Assert after first click on Next button
        var buttonNext1 = cut.Find("fluent-button[appearance='accent']");
        buttonNext1.Click();

        int clickableLinks2 = cut.FindAll("li[style*='cursor: pointer']").Count;
        Assert.Equal(clickable2, clickableLinks2);

        // Assert after a second click on Next button
        var buttonNext2 = cut.Find("fluent-button[appearance='accent']");
        buttonNext2.Click();

        int clickableLinks3 = cut.FindAll("li[style*='cursor: pointer']").Count;
        Assert.Equal(clickable3, clickableLinks3);

        // Click on the first step
        var step1 = cut.FindAll("li")[0];
        step1.Click();

        Assert.Equal(indexFirstItem, currentIndex);
    }

    [Theory]
    [InlineData(true, true, true, 2)]
    [InlineData(true, true, false, 1)]
    [InlineData(true, false, false, 0)]
    [InlineData(false, false, false, 0)]
    public void FluentWizard_LastDisableSteps(bool firstEnabled, bool secondEnabled, bool thirdEnabled, int nbClicks)
    {
        // Arrange
        var cut = Render(@<FluentWizard>
        <Steps>
            <FluentWizardStep Disabled="@(!firstEnabled)" />
            <FluentWizardStep Disabled="@(!secondEnabled)" />
            <FluentWizardStep Disabled="@(!thirdEnabled)" />
        </Steps>
    </FluentWizard>
    );

        // Act: Click
        for (int i = 0; i < nbClicks; i++)
        {
            var buttonNext = cut.Find("fluent-button[appearance='accent']");
            buttonNext.Click();
        }

        // Assert
        Assert.Contains("Done", cut.Markup);
    }

    private record TestRecord
    {
        [Range(1, 10)]
        public int? NumberBetween1and10 { get; set; }
    }
}
